home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers1.zip / ISOLINK.ASM < prev    next >
Assembly Source File  |  1992-01-23  |  54KB  |  1,633 lines

  1.     page 54,132
  2. ; Packet driver for BICC Data Networks' ISOLINK 4110-2 ethernet
  3. ; controller, written by
  4. ;       Rainer Toebbicke
  5. ;       European Organisation of Nuclear Research (CERN)
  6. ;       Geneva, Switzerland
  7. ; based on the "generic" packet driver by Russell Nelson.
  8.  
  9. version equ     2               ;this is the minor version
  10.  
  11.         include defs.asm        ;SEE ENCLOSED COPYRIGHT MESSAGE
  12.  
  13. ; BICC ISOLINK card constants
  14.  
  15.  
  16.  
  17.         .286c                   ; we are at least on a 80286!
  18.  
  19.  
  20. code    segment para public
  21.         assume  cs:code, ds:code
  22.         public  begin   ;makes us appear in the link map
  23. begin   equ     $       ;used for alignment operations below
  24.  
  25. ;Lance initialisation block, must be on word boundary
  26.  
  27. ;
  28. ;     Initialization Block  Mode operation Bit Definitions.
  29. ;
  30. M_PROM        equ    8000h    ; Promiscuous Mode
  31. M_INTL        equ    0040h   ; Internal Loopback
  32. M_DRTY        equ    0020h   ; Disable Retry
  33. M_COLL        equ    0010h    ; Force Collision
  34. M_DTCR        equ    0008h    ; Disable Transmit CRC)
  35. M_LOOP        equ    0004h    ; Loopback
  36. M_DTX        equ    0002h    ; Disable the Transmitter
  37. M_DRX        equ    0001h   ; Disable the Reciever
  38.  
  39. IBmode          dw      00h             ;mode word
  40. IBpadr          db      6 dup (0)       ;physical addr
  41. IBladrf         db      8 dup (0ffh)    ;logical addr filter
  42. IBrdraL         dw      0               ;Receive Descr Ring ptr
  43. IBrdraH         dw      0
  44. IBrdraHF        equ     byte ptr IBrdraH+1
  45. IBtdraL         dw      0               ;Transmit Descr Ring ptr
  46. IBtdraH         dw      0
  47. IBtdraHF        equ     byte ptr IBtdraH+1
  48.  
  49.  
  50. CSR0            equ     0
  51. c0_ERR          equ     8000h
  52. c0_BABL         equ     4000h
  53. c0_CERR         equ     2000h
  54. c0_MISS         equ     1000h
  55. c0_MERR         equ     0800h
  56. c0_RINT         equ     0400h
  57. c0_TINT         equ     0200h
  58. c0_ErrClear     equ     c0_BABL+c0_CERR+c0_MISS+c0_MERR
  59.  
  60. c0_IDON         equ     0100h
  61. c0_INTR         equ     0080h
  62. c0_INEA         equ     0040h
  63. c0_RXON         equ     0020h
  64. c0_TXON         equ     0010h
  65. c0_TDMD         equ     0008h
  66. c0_STOP         equ     0004h
  67. c0_STRT         equ     0002h
  68. c0_INIT         equ     0001h
  69.  
  70.  
  71. CSR1            equ     1
  72. CSR2            equ     2
  73. CSR3            equ     3
  74.  
  75.  
  76.  
  77. RD              struc                   ;Receive descriptor
  78. RBadrL          dw      0
  79. RBadrH          dw      0
  80. RBbcnt          dw      0               ;buffer size
  81. RBmcnt          dw      0               ;packet size
  82. RD              ends
  83.  
  84. RBflags         equ     byte ptr RBadrH+1
  85. RBown           equ     080h            ;1=owned by Lance, 0=by host
  86. RBerr           equ     040h            ;error summary bit
  87. RBfram          equ     020h
  88. RBoflo          equ     010h
  89. RBcrc           equ     008h
  90. RBbuff          equ     004h
  91. RBstp           equ     002h            ;start of packet
  92. RBenp           equ     001h            ;end of packet
  93.  
  94. TD              struc                   ;Transmit descriptor
  95. TBadrL          dw      0
  96. TBadrH          dw      0
  97. TBbcnt          dw      0               ;buffer size
  98. TBtdr           dw      0               ;more flags
  99. TD              ends
  100.  
  101. TBflags         equ     byte ptr TBadrH+1
  102. TBown           equ     080h            ;1=owned by Lance, 0=by host
  103. TBerr           equ     040h            ;error summary bit
  104. TBstp           equ     002h            ;Start of packet
  105. TBenp           equ     001h            ;End of packet
  106. TBbcntF         equ     byte ptr TBbcnt+1
  107.  
  108. gary            db      0               ; DEBUG
  109. garycount       db      0               ; DEBUG
  110.  
  111.         public  int_no
  112. int_no  dw      10,0                     ;must be four bytes long for get_number.
  113.  
  114.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  115. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  116. driver_type     db      5               ;from the packet spec
  117. driver_name     db      'ISOLINK',0     ;name of the driver.
  118. driver_function    db    2
  119. parameter_list    label    byte
  120.     db    1    ;major rev of packet driver
  121.     db    9    ;minor rev of packet driver
  122.     db    14    ;length of parameter list
  123.     db    EADDR_LEN    ;length of MAC-layer address
  124.     dw    GIANT    ;MTU, including MAC headers
  125.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  126.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  127.     dw    0    ;(# of successive xmits) - 1
  128. int_num    dw    0    ;Interrupt # to hook for post-EOI
  129.             ;processing, 0 == none,
  130.  
  131.     extrn    sys_features: byte
  132.  
  133.         public  rcv_modes
  134. rcv_modes       dw      7         ;number of receive modes in our table.
  135.                 dw      0
  136.                 dw      rcv_mode_1
  137.                 dw      0
  138.                 dw      rcv_mode_3
  139.                 dw      0,0
  140.                 dw      rcv_mode_6
  141.  
  142. rbfstart        dw      FirstDescr      ;1st Rcv buffer descr
  143. rbfcurr         dw      ?
  144. tbfstart        dw      ?               ;1st Xmit buffer descr
  145. tbfcurr         dw      ?
  146. tbfend          dw      ?               ;end of Xmit buffers
  147.  
  148. xmt_buffsz_r    dw      ?               ;xmit buffer sizes
  149. xmt_buffsz_rn   dw      ?               ;same, but times -1
  150. pklen           dw      ?               ;length of packet
  151. pklen_rem       dw      ?               ;remaining to be received
  152. rcv_csr0        dw      ?
  153. rcvbuffp        dd      ?
  154.  
  155.  
  156. RAP             dw      0               ;Register Address Port
  157. RDP             dw      0               ;Register Data Port
  158.  
  159. DMAPrt          db      0,0,0,0        ;DMA port number.
  160.  
  161. options         db      0
  162. options_HMA     equ     40h             ;running in HMA
  163.  
  164. word_16         dw      16
  165.  
  166.  
  167. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  168. ;       Gary Spanswick - 3/5/90
  169. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  170.  
  171. CACPCtrl        equ     90h             ; Address of CACP control register
  172.  
  173. DMACascade      EQU     0D0H        ; DMA Operates in Cascaded Mode
  174. DMAUnmask       EQU     00H        ; DMA Operation is to unmask
  175. DMAC1ModeReg    EQU     0BH        ; DMA Mode Register Address
  176. DMAC2ModeReg    EQU     0D6H        ; DMA Mode Register Address
  177. DMAC1MaskReg    EQU     0AH        ; DMA Mask Register Address
  178. DMAC2MaskReg    EQU     0D4H        ; DMA Mask Register Address
  179.  
  180.  
  181. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  182.  
  183.                 extrn   count_out_err:near, count_in_err:near
  184.  
  185.  
  186. seg2lin         proc    near
  187. ; convert (ax:dx=offset:segment) to linear address (ax:dx=low:high)
  188.                 push    bx
  189.                 push    ax              ;save offset
  190.                 mov     ax,dx
  191.                 mul     word_16         ;segment to linear address
  192.                 pop     bx
  193.                 add     ax,bx           ;plus offset
  194.                 adc     dx,0
  195.                 pop     bx              ;restore
  196.                 ret
  197. seg2lin         endp
  198.  
  199.  
  200. lin2seg         proc    near
  201. ; convert linear addr (ax:dx=low:high) to (ax:dx=offset:segment)
  202. ; with minimal offset to avoid wrap-around problems
  203.  
  204. ; the 80286 can address 0-10ffefh in real mode:
  205.                 cmp     dl,010h         ;over 1 Megabyte?
  206.                 je      l2sHMA          ;yes, segment is 0FFFFh
  207.                 push    ax
  208.                 shr     ax,4            ;convert to paragraphs
  209.                 shl     dx,4+8
  210.                 or      dx,ax           ;segment ok
  211.                 pop     ax
  212.                 and     ax,0fh          ;offset
  213.                 ret
  214.  
  215.  
  216. l2sHMA:
  217. ; effectively subtract 0ffff0h from the linear address to form the
  218. ; offset:
  219.                 mov     dx,0ffffh       ;this we know already
  220.                 sub     ax,0fff0h       ;only have to do low order word
  221.                 ret
  222. lin2seg         endp
  223.  
  224.  
  225. ; write bx to Lance control & status reg [ax]
  226. wrcsr0          proc    near
  227.                 xor     ax,ax           ;write to CSR0
  228. wrcsr:                                  ;CSR in ax
  229.                 mov     dx,RAP          ;address CSR
  230.                 out     dx,ax
  231.                 mov     dx,RDP          ;data port
  232.                 mov     ax,bx
  233.                 out     dx,ax
  234.                 ret
  235. wrcsr0          endp
  236.  
  237.  
  238. ; read Lance control reg [ax]
  239. rdcsr0          proc    near
  240.                 xor     ax,ax           ;read CSR 0
  241. rdcsr:                                  ;CSR in ax
  242.                 mov     dx,RAP
  243.                 out     dx,ax
  244.                 mov     dx,RDP
  245.                 in      ax,dx
  246.  
  247.                 ret
  248. rdcsr0          endp
  249.  
  250.  
  251. rcv_nxt_d       proc    near
  252. ; release current and advance to next receive descriptor
  253.                 mov     RBflags[bx],RBown       ;give buffer to Lance
  254.                 add     bx,8
  255.                 cmp     bx,tbfstart     ;end of ring?
  256.                 jb      rcv_nxt_ok      ;no...
  257.                 mov     bx,rbfstart     ;restart at first descriptor
  258. rcv_nxt_ok:
  259.                 mov     rbfcurr,bx
  260.                 ret
  261. rcv_nxt_d       endp
  262.  
  263.  
  264. xmt_nxt_d       proc    near
  265. xmt_nxt_d       endp
  266.  
  267.  
  268. wait_own_0      proc    near
  269. ; wait for "own" bit in descriptor [bx] to clear
  270.                 test    TBflags[bx],TBown
  271.                 jnz     wo_wait                 ;no, have to wait
  272.                 ret
  273.  
  274. wo_wait:
  275.                 push    cx                      ;save reg
  276.                 mov     cx,0ffffh
  277. wo_lp1:
  278.                 test    TBflags[bx],TBown
  279.                 jz      wo_clear                ;ok...
  280.                 loop    wo_lp1
  281.  
  282. wo_clear:
  283.                 pop     cx
  284.                 ret
  285. wait_own_0      endp
  286.  
  287.  
  288. rcv_getaddr     proc    near
  289. ; obtain buffer addr from descriptor [bx]
  290.                 mov     ax,RBadrL[bx]
  291.                 mov     dx,RBadrH[bx]
  292.                 call    lin2seg
  293.                 mov     word ptr rcvbuffp,ax
  294.                 mov     word ptr rcvbuffp+2,dx
  295.                 ret
  296. rcv_getaddr     endp
  297.  
  298.     public    as_send_pkt
  299. ; The Asynchronous Transmit Packet routine.
  300. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  301. ;   interrupts possibly enabled.
  302. ; Exit with nc if ok, or else cy if error, dh set to error number.
  303. ;   es:di and interrupt enable flag preserved on exit.
  304. as_send_pkt:
  305.     ret
  306.  
  307.     public    drop_pkt
  308. ; Drop a packet from the queue.
  309. ; Enter with es:di -> iocb.
  310. drop_pkt:
  311.     assume    ds:nothing
  312.     ret
  313.  
  314.     public    xmit
  315. ; Process a transmit interrupt with the least possible latency to achieve
  316. ;   back-to-back packet transmissions.
  317. ; May only use ax and dx.
  318. xmit:
  319.     assume    ds:nothing
  320.     ret
  321.  
  322.  
  323. ErrExit         proc    near
  324.                 mov     ah,9
  325.                 int     21h
  326.                 stc
  327.                 ret
  328. ErrExit         endp
  329.  
  330. LoadInitBlock   proc    near
  331. ; set initialisation block addr
  332.                 push    ds
  333.                 pop     dx
  334.                 mov     ax,offset IBmode
  335.                 call    seg2lin
  336.                 push    dx              ;don't loose it
  337.                 mov     bx,ax
  338.                 mov     ax,CSR1
  339.                 call    wrcsr           ;low order 16 bits of addr
  340.                 pop     bx
  341.                 mov     ax,CSR2
  342.                 call    wrcsr           ;high order bits
  343.                 ret
  344. LoadInitBlock   endp
  345.  
  346. InitLance       proc    near
  347. ; init the controller and wait for completion
  348.                 mov     bx,c0_INIT
  349.                 call    wrcsr0
  350.  
  351.                 mov     cx,-1           ;wait for completion
  352. eto_initlp:
  353.                 call    rdcsr0
  354.                 test    ax,c0_IDON      ;done?
  355.                 jnz     init_ok         ;good!
  356.                 loop    eto_initlp
  357.  
  358.                 mov     dx,offset init_errmsg
  359.                 call    outofHMA        ;get out of HMA
  360.                 call    errexit
  361. init_ok:
  362.                 ret
  363. InitLance       endp
  364.  
  365.  
  366.         public  send_pkt
  367. send_pkt        proc    near
  368. ;enter with ds:si -> packet, cx = packet length.
  369. ;exit with nc if ok, or else cy if error, dh set to error number.
  370.         assume  ds:nothing
  371.                 push    ds              ;save packet segment
  372.                 push    cs
  373.                 pop     ds
  374.                 assume  ds:code
  375.  
  376. ; packet must be at least 64 bytes long (with fcs)...
  377.  
  378.                 cmp     cx, 82          ; DEBUG
  379.                 jb      Fred1           ; DEBUG
  380.                 mov     gary,1          ; DEBUG
  381. Fred1:                                  ; DEBUG
  382.  
  383.                 cmp     gary,1
  384.                 jne     fred2
  385.                 inc     garycount
  386. fred2:
  387.  
  388.                 cmp     cx,RUNT
  389.                 jnl     send_L_ok
  390.                 mov     cl,RUNT
  391. send_L_ok:
  392.  
  393. ; get next buffer descriptor
  394.                 mov     bx,tbfcurr
  395.                 call    wait_own_0      ;wait until it's free
  396.  
  397. ; If the next buffer is big enough to hold the packet, we will
  398. ; copy the packet and send it out.
  399. ; Otherwise we send it from the user's buffer but then have to
  400. ; wait until it is sent out.
  401. ; This may speed up fast machines on the expense of some memory
  402.  
  403.                 cmp     cx,xmt_buffsz_r ;longer than our buffers?
  404.                 jng     send_copy       ;no, copy the packet
  405.  
  406. send_user_buff:                         ;send from user's buffer
  407.                 mov     ax,si           ;input buffer addr
  408.                 pop     dx              ;segment
  409.                 call    seg2lin         ;convert to linear addr
  410.                 push    TBadrL[bx]      ;save original buffer address
  411.                 push    TBadrH[bx]      ;...
  412.                 mov     TBadrL[bx],ax
  413.                 mov     TBadrH[bx],dx
  414.                 jmp     short send_send
  415.  
  416. send_copy:
  417.                 mov     ax,TBadrL[bx]
  418.                 mov     dx,TBadrH[bx]   ;buffer address
  419.                 call    lin2seg         ;convert to offset:segment
  420.                 mov     es,dx
  421.                 mov     di,ax
  422.                 pop     ds              ;restore packet segment
  423.                 assume  ds:nothing
  424.                 push    cx              ;save length
  425.                 test    cx,1            ;uneven length?
  426.                 jz      send_even
  427.                 movsb
  428. send_even:
  429.                 shr     cx,1            ;convert to words, can't be zero
  430.                 rep     movsw           ;copy buffer
  431.                 pop     cx
  432.                 push    cs
  433.                 pop     ds              ;restore ds
  434.                 assume  ds:code
  435.  
  436. send_send:
  437.                 neg     cx              ;length in two's complement
  438.                 mov     TBbcnt[bx],cx
  439.                 or      TBflags[bx],TBown+TBstp+TBenp
  440.                 push    bx              ;save ring entry address
  441.                 mov     bx,c0_TDMD+c0_INEA
  442.                 call    wrcsr0          ;start transmitter immediately
  443.                 pop     bx              ;restore ring entry addr
  444.                 xor     al,al           ;assume no error
  445.                 cmp     cx,xmt_buffsz_rn ;was this a big buffer?
  446.                 jnl     send_next       ;no, all done
  447.  
  448.                 call    wait_own_0      ;wait for send ok
  449.                 mov     al,TBflags[bx]  ;save flags
  450.                 mov     cx,xmt_buffsz_rn ;original buffer size negated
  451.                 pop     TBadrH[bx]
  452.                 pop     TBadrL[bx]
  453.                 mov     TBbcnt[bx],cx
  454.  
  455.  
  456.  
  457. ; advance to next transmit descriptor
  458. send_next:
  459.                 add     bx,8
  460.                 cmp     bx,tbfend       ;end of ring?
  461.                 jb      xmt_nxt_ok      ;no...
  462.                 mov     bx,tbfstart     ;restart at first descriptor
  463. xmt_nxt_ok:
  464.                 mov     tbfcurr,bx
  465.  
  466. send_done:
  467.                 test    al,TBerr        ;were there problems?
  468.                 jnz     send_err
  469.                 clc
  470.                 ret
  471.  
  472. send_err:
  473.                 call    count_out_err
  474.                 stc
  475.                 ret
  476. send_pkt        endp
  477.  
  478.  
  479.         public  get_address
  480. get_address:
  481. ;get the address of the interface.
  482. ;enter with es:di -> place to get the address, cx = size of address buffer.
  483. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  484.         assume  ds:code
  485.         cmp     cx,EADDR_LEN
  486.         jnb     get_addr_ok             ;buffer ok
  487.         stc
  488.         ret
  489.  
  490. get_addr_ok:
  491.         push    si
  492.         mov     si,offset IBpadr
  493.         rep     movsb
  494.         pop     si
  495.         mov     cl,EADDR_LEN
  496.         clc
  497.         ret
  498.  
  499.  
  500.  
  501.         public  set_address
  502. set_address:
  503. ;enter with ds:si -> Ethernet address, CX = length of address.
  504. ;exit with nc if okay, or cy, dh=error if any errors.
  505.         assume  ds:nothing
  506.         cmp     cx,EADDR_LEN
  507.         jnb     set_addr_ok             ;buffer ok
  508.         mov     dh,BAD_ADDRESS
  509.         stc
  510.         ret
  511.  
  512. set_addr_ok:
  513.         assume  es:nothing
  514.         clc
  515.         ret
  516.  
  517.  
  518. reset_mode      proc    near
  519. ; stop and restart the receiver
  520.                 call    reset_interface         ;stop it
  521.                 mov     bx,c0_INIT              ;re-init
  522.                 call    wrcsr0
  523.                 mov     cx,-1                   ;wait until done
  524. rm_lp:
  525.                 call    rdcsr0
  526.                 test    ax,c0_IDON              ;ok?
  527.                 jnz     rm_IDON                 ;yes...
  528.                 loop    rm_lp                   ;else continue
  529.  
  530. rm_IDON:
  531.                 mov     bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON
  532.                 call    wrcsr0                  ;start the receiver
  533.                 ret
  534. reset_mode      endp
  535.  
  536.  
  537. rcv_mode_1:
  538.                 mov     IBmode,M_DRX or M_DTX
  539.                 jmp     reset_mode
  540.  
  541.  
  542. rcv_mode_3:
  543.                 mov     IBmode,0
  544.                 jmp     reset_mode
  545.  
  546. rcv_mode_6:
  547.                 mov     IBmode,M_PROM
  548.                 jmp     reset_mode
  549.  
  550.  
  551.         public  set_multicast_list
  552. set_multicast_list:
  553. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  554. ;return nc if we set all of them, or cy,dh=error if we didn't.
  555.         mov     dh,NO_MULTICAST
  556.         stc
  557.         ret
  558.  
  559.  
  560.     public    terminate
  561. terminate:
  562.     call    rcv_mode_1        ;don't receive any apckets.
  563.  
  564. ;This routine will remove the (host) DMA controller from
  565. ;cascade mode of operation.
  566.     mov    al,DMAPrt
  567.     or    al,4
  568.     cmp    DMAPrt,4        ;If channel 5 or 6,
  569.     ja    terminate_16        ;  use sixteen bit dma.
  570. terminate_8:
  571.     out    DMAC1MaskReg,al
  572.     jmp    short terminate_done
  573. terminate_16:
  574.     out    DMAC2MaskReg,al
  575. terminate_done:
  576.     ret
  577.  
  578.  
  579.         public  get_multicast_list
  580. get_multicast_list:
  581. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  582. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  583. ;return cy, NO_MULTICAST if we don't implement multicast.
  584.         mov     dh,NO_MULTICAST
  585.         stc
  586.         ret
  587.  
  588.  
  589.  
  590.         public  reset_interface
  591. reset_interface proc    near
  592. ;reset the interface.
  593.                 assume  ds:code
  594.                 mov     bx,c0_STOP
  595.                 call    wrcsr0
  596.                 ret
  597. reset_interface endp
  598.  
  599.  
  600. ;called when we want to determine what to do with a received packet.
  601. ;enter with cx = packet length, es:di -> packet type.
  602.         extrn   recv_find: near
  603.  
  604. ;called after we have copied the packet into the buffer.
  605. ;enter with ds:si ->the packet, cx = length of the packet.
  606.         extrn   recv_copy: near
  607.  
  608.  
  609.         public  recv
  610. recv    proc    near
  611. ;called from the recv isr.  All registers have been saved, and ds=cs.
  612. ;Upon exit, the interrupt will be acknowledged.
  613.         assume  ds:code
  614.  
  615.         call    rdcsr0                  ;obtain interrupting status
  616.         and     ax,0ffffh-c0_INEA       ;disable interrupts
  617. ;        mov     RXStatus,Active         ;Indicate receive is active
  618.         mov     bx,ax
  619.         call    wrcsr0                  ;clear acknowledged i-sources
  620.  
  621.         mov     rcv_csr0,bx             ;save
  622. ;       test    bx,c0_ERR               ;any errors?
  623. ;       jz      rcv_noerr               ;no...
  624. ;       ...     errors checked on descriptor level
  625.  
  626. rcv_noerr:
  627.         test    bx,c0_RINT              ;received a packet
  628.         jz      rcv_norint
  629.         call    do_rcv                  ;process...
  630.  
  631. rcv_norint:
  632.  
  633. rcv_ret:
  634.         mov     bx,c0_INEA              ;re-enable interrupts
  635.         cli
  636.         call    wrcsr0
  637.         ret
  638. recv    endp
  639.  
  640.  
  641.  
  642. do_rcv          proc    near
  643.                 
  644.                 mov     bx,rbfcurr              ;address descriptor
  645. rcv_lp:
  646.                 mov     al,RBflags[bx]
  647.                 test    al,RBown                ;something in buffer?
  648.                 jz      rcv_dobuf               ;yes...
  649.                 ret                             ;else return
  650.  
  651. rcv_dobuf:
  652.                 test    al,RBerr                ;any errors?
  653.                 jz      rcv_good                ;no...
  654.                 test    al,RBoflo               ;overflow bit set?
  655.                 jz      rcv_err_1               ;no...
  656.                 test    al,RBenp                ;ghost overflow error?
  657.                 jnz     rcv_good                ;yes, ignore the error
  658.  
  659. rcv_err_1:
  660.  
  661. rcv_do_err:
  662. ;               test    al,RBoflo+RBbuff        ;only count these
  663. ;               jz      rcv_next
  664.  
  665.                 call    count_in_err
  666.  
  667. rcv_next:
  668.                 call    rcv_nxt_d               ;next descriptor
  669.                 jmp     rcv_lp
  670.  
  671. rcv_good:
  672.                 test    al,RBstp        ;packet starts here?
  673.                 jz      rcv_do_err      ;no, unrolling error chain,
  674.                                         ;count when error flag appears
  675.  
  676. rcv_good_stp:
  677. ; obtain packet length from last segment
  678. rcv_L_lp:
  679.                 test    al,RBenp                ;end of packet?
  680.                 jnz     rcv_L_ok                ;yes, get length
  681.                 add     bx,8                    ;to next descriptor
  682.                 cmp     bx,tbfstart             ;overrun?
  683.                 jb      rcv_L_next              ;no...
  684.                 mov     bx,rbfstart
  685. rcv_L_next:
  686.                 cmp     bx,rbfcurr              ;make sure we don't loop!
  687.                 je      rcv_L_ouch              ;this is nonsense
  688.                 mov     al,RBflags[bx]          ;get flags
  689.                 test    al,RBown+RBerr          ;anything wrong with it?
  690.                 jz      rcv_L_lp                ;no, go ahead
  691.                 mov     dl,al
  692.                 and     dl,RBenp+RBoflo
  693.                 cmp     dl,RBenp+RBoflo         ;ghost overflow?
  694.                 je      rcv_L_ok                ;yes, let it go through
  695.  
  696. rcv_L_ouch:
  697.                 mov     bx,rbfcurr              ;restore current
  698.                 jmp     rcv_do_err              ;give up
  699.  
  700. rcv_L_ok:
  701.                 mov     cx,RBmcnt[bx]           ;message length
  702.                 sub     cx,4                    ;strip FCS
  703.                 mov     bx,rbfcurr              ;restore descriptor addr
  704.                 cmp     cx,GIANT                ;reasonable size?
  705.                 jg      rcv_do_err              ;rubbish!
  706.                 jcxz    rcv_next                ;nothing to do...
  707.                 mov     pklen,cx                ;save packet length
  708.                 mov     pklen_rem,cx            ;remains to be rcvd
  709.  
  710.                 call    rcv_getaddr
  711.  
  712.                 mov     di,ax
  713.                 mov     es,dx
  714.                 add     di,EADDR_LEN*2          ;point to type field
  715.  
  716.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  717.     mov    ax, es:[di]
  718.     xchg    ah, al
  719.     cmp     ax, 1500
  720.     ja    BlueBookPacket
  721.     inc    di            ;set di to 802.2 header
  722.     inc    di
  723.     mov    dl, IEEE8023
  724. BlueBookPacket:
  725.  
  726.                 call    recv_find               ;want this packet?
  727.  
  728.                 mov     ax,es
  729.                 or      ax,di
  730.                 mov     bx,rbfcurr              ;restore in case...
  731.                 jz      rcv_next                ;no buffer, give up
  732.  
  733.                 push    es
  734.                 push    di
  735. rcv_seg_lp:
  736. ; the packet's segments are copied into the client's buffer.
  737. ; The calculated length did not include the 4 byte fcs. Care must
  738. ; be taken not to copy the fcs, which may (in the worst case) be
  739. ; part of the last two segments!
  740.  
  741.                 test    RBflags[bx],RBenp       ;packet ends here?
  742.                 jz      rcv_seg_l_buf           ;no, use buffer size
  743.                 mov     cx,pklen_rem            ;remaining msg length
  744.                 or      cx,cx                   ;still data?
  745.                 jle     rcv_done                ;no, just part of fcs
  746.                 jmp     short rcv_seg_l_ok
  747.  
  748. rcv_seg_l_buf:
  749.                 mov     cx,RBbcnt[bx]           ;buffer size
  750.                 neg     cx                      ;it's in two's complement
  751.                 sub     pklen_rem,cx            ;correct remaining len
  752.                 jnl     rcv_seg_l_ok            ;use whole buffer
  753. ; the current buffer contains part of the fcs...
  754.                 add     cx,pklen_rem            ;use only data part
  755.  
  756. rcv_seg_l_ok:
  757.                 lds     si,rcvbuffp             ;point to buffer
  758.                 assume  ds:nothing
  759.                 test    cl,1                    ;prepare for movsw
  760.                 jz      rcv_even
  761.                 movsb                           ;copy first byte
  762. rcv_even:
  763.                 shr     cx,1
  764.                 jcxz    rcv_moved
  765.                 rep     movsw                   ;copy the packet
  766.  
  767. rcv_moved:
  768.                 push    cs
  769.                 pop     ds
  770.                 assume  ds:code
  771.  
  772.                 test    RBflags[bx],RBenp       ;end of packet?
  773.                 jnz     rcv_done                ;yes...
  774.  
  775.                 call    rcv_nxt_d               ;to next descriptor
  776.                 call    rcv_getaddr             ;next buffer addr
  777.                 jmp     rcv_seg_lp
  778.  
  779. rcv_done:
  780.                 mov     cx,pklen
  781.                 pop     si                      ;restore buffer addr
  782.                 pop     ds
  783.                 assume  ds:nothing
  784.  
  785.                 call    recv_copy               ;wake up client
  786.  
  787.                 push    cs
  788.                 pop     ds
  789.                 assume  ds:code
  790.  
  791.                 mov     bx,rbfcurr              ;current descriptor
  792.                 jmp     rcv_next                ;else do next descriptor
  793.  
  794. do_rcv          endp
  795.  
  796.  
  797.         public  recv_exiting
  798. recv_exiting:
  799. ;called from the recv isr after interrupts have been acknowledged.
  800. ;Only ds and ax have been saved.
  801.         assume  ds:nothing
  802.         ret
  803.  
  804.  
  805. ; Most of the initialisation code is used only once and can be
  806. ; dicarded when init finishes, but not this:
  807. ; we formatted the buffer descriptors (a maximum space for
  808. ; that could be provided), but where could we place this code
  809. ; if buffers are allocated immediately afterwards?
  810. ; Too dangerous in the buffer area, since we will start the receiver now.
  811. ; Possible alternative: relocate to an address after the buffers, but
  812. ; since it's only a few bytes...
  813.  
  814. eto_go:
  815.         assume  ds:code
  816.         call    wrcsr           ;start the Lance
  817.         pop     dx              ;get our ending paragraph
  818.         mov     ah,31h
  819.         int     21h             ;terminate, stay resident
  820.  
  821.  
  822. ; Provide maximum space for buffer descriptors before more
  823. ; discardable initialisation code starts, since the decriptors
  824. ; must be formatted. Buffers may follow immediately afterwards,
  825. ; but will not be used until the receiver is started.
  826.  
  827. ; All resident code and data must be before this label!
  828. ; on quadword boundary...
  829. public  buffers_start
  830. buffers_start   db      0
  831.  
  832.                 org     begin+( (($-begin+7)/8)*8 )
  833. FirstDescr      db      ((128+128)*8) dup (0)
  834.  
  835.  
  836.  
  837.         public  usage_msg
  838. usage_msg   db  "usage: ISOLINK [-n] [-d] [-w] <packet_int_no> <options>",CR,LF
  839.         db      "options:       [defaults]",CR,LF
  840.         db      "  /D<DMA channel #> [0]",CR,LF
  841.         db      "  /I<hw-int-level> [10]",CR,LF
  842.         db      "  /P<I/O port address> [(8)280]",CR,LF
  843.         db      "  /R<# recv buffs> <recv buff size> [16 256]",CR,LF
  844.         db      "  /T<# xmit buffs> <xmit buff size> [1 0]",CR,LF
  845.         db      "  /X (requires himem.sys installed)",CR,LF
  846.         db      "$"
  847.  
  848.  
  849.  
  850.  
  851.         public  copyright_msg
  852. copyright_msg   db  "Packet driver for BICC 4110-2/3 ISOLAN controllers,"
  853.         db  "version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  854.                 db  "Written by R.Toebbicke, CERN, Switzerland",CR,LF
  855.  db "*     Copyright CERN, Geneva 1990 - Copyright and any other",CR,LF
  856.  db "*     appropriate legal protection of these computer programs",CR,LF
  857.  db "*     and associated documentation reserved in all countries",CR,LF
  858.  db "*     of the world.",CR,LF,'$'
  859.  
  860.  
  861.  
  862. int_no_name     db      "Interrupt number $"
  863. BaseName        db      "I/O Port address $"
  864. BasePrt         dw      08280h,0
  865. DMAName         db      "DMA channel number $"
  866.  
  867.         extrn   our_isr: near, their_isr: dword
  868.         extrn   packet_int_no: byte
  869.         extrn   phd_environ: word
  870.         extrn   decout: near
  871.  
  872. rcv_buffno      dw      16,0
  873. rcv_buffnoname  db      "Number of receive buffers $"
  874. rcv_bufflog     db      4
  875. rcv_buffsz      dw      256,0
  876. rcv_buffszname  db      "Receive buffer size $"
  877. xmt_buffno      dw      1,0
  878. xmt_buffnoname  db      "Number of transmit buffers $"
  879. xmt_bufflog     db      0
  880. xmt_buffsz      dw      0,0
  881. xmt_buffszname  db      "Transmit buffer size $"
  882.  
  883. orgseg          dw      ?
  884.  
  885. linaddrL        dw      0
  886. linaddrH        dw      0
  887.  
  888. ; keep these two together!
  889. HMAaddr         dw      00010h
  890. HMAaddrS        dw      0FFFFh
  891.  
  892. XMSctl          dd      ?
  893.  
  894. PS2IO           dw      08280h, 09250h, 0a390h, 0b1d0h
  895. PS2INT          db      9, 10, 11, 15, 3, 4, 5, 0
  896.  
  897.  
  898.         extrn   set_recv_isr: near
  899.  
  900. ;enter with si -> argument string, di -> word to store.
  901. ;if there is no number, don't change the number.
  902.     extrn    get_number: near
  903.  
  904. ;enter with dx -> name of word, di -> dword to print.
  905.     extrn    print_number: near
  906.  
  907.         extrn   skip_blanks: near
  908.  
  909. argerr          db      "Error in options: '"
  910. argerrc         db      " "
  911.                 db      "'.",CR,LF,"$"
  912.  
  913. parse_err       db      0
  914.  
  915.  
  916.         public  parse_args
  917. parse_args      proc    near
  918. ; If we run on a PS/2, read the default configuration from the POS regs
  919.  
  920.     test    sys_features,MICROCHANNEL
  921.     jnz    do_mc_defaults
  922.     jmp    parse_args_l
  923. do_mc_defaults:
  924.  
  925.                 mov     bx,08h                  ;1st slot
  926. pa_slot_l:
  927.                 mov     dx,96h
  928.                 mov     ax,bx
  929.                 out     dx,al                   ;put in setup mode
  930.                 mov     dx,101h
  931.                 in      al,dx
  932.                 xchg    al,ah                   ;high id byte
  933.                 dec     dx
  934.                 in      al,dx                   ;low id byte
  935.                 cmp     ax,0808h                ;ISOLINK card?
  936.                 je      pa_found_iso            ;yes...
  937.                 inc     bx                      ;next slot
  938.                 cmp     bx,0fh                  ;too far?
  939.                 jna     pa_slot_l               ;no, try next
  940.                 mov     dx,96h
  941.                 xor     al,al
  942.                 out     dx,al                   ;exit setup mode
  943.                 jmp     parse_args_l
  944.  
  945. pa_found_iso:
  946.                 mov     dx,102h
  947.                 in      al,dx                   ;get I/O address code
  948.                 xor     ah,ah
  949.                 and     al,6
  950.                 mov     bx,ax
  951.                 mov     ax,PS2IO[bx]            ;I/O port address
  952.                 mov     BasePrt,ax
  953.  
  954.                 mov     dx,104h
  955.                 in      al,dx
  956.                 xor     ah,ah
  957.                 shr     al,5                    ;isolate interrupt bits
  958.                 mov     bx,ax
  959.                 mov     al,PS2INT[bx]           ;interrupt number
  960.                 mov     int_no,ax
  961.  
  962.  
  963. parse_args_l:
  964.         call    skip_blanks
  965.         cmp     al,CR           ;end of args?
  966.         je      pa_ret          ;yes...
  967.         cmp     al,'/'          ;option following?
  968.         je      pa_doopt        ;yes
  969.  
  970. pa_err:
  971.         mov     argerrc,al
  972.         mov     dx,offset argerr
  973.  
  974. pa_err2:
  975.         mov     ah,9
  976.         int     21h             ;print error message
  977.         mov     parse_err,1     ;indicate error
  978. pa_ret:
  979.         ret
  980.  
  981. pa_doopt:
  982.         inc     si
  983.         lodsb                   ;get option byte
  984.         cmp     al,'a'          ;in lowercase range?
  985.         jna     pa_upper
  986.         sub     al,20h          ;convert to uppercase
  987. pa_upper:
  988.         cmp     al,'I'
  989.         je      pa_doInt
  990.         cmp     al,'P'
  991.         je      pa_doPort
  992.         cmp     al,'D'
  993.         je      pa_doDMA
  994.         cmp     al,'R'
  995.         je      pa_doRcv
  996.         cmp     al,'T'
  997.         je      pa_doTrans
  998.         cmp     al,'X'                  ;into extended memory?
  999.         je      pa_doext
  1000.         jmp     pa_err
  1001.  
  1002. pa_doInt:
  1003.         mov     di,offset int_no
  1004.         call    get_number
  1005.         jmp     parse_args_l
  1006.  
  1007. pa_doPort:
  1008.         mov     di,offset BasePrt
  1009.         call    get_number
  1010.         jmp     parse_args_l
  1011.  
  1012. pa_doDMA:
  1013.         mov     di,offset DMAPrt
  1014.         call    get_number
  1015.         jmp     parse_args_l
  1016.  
  1017.  
  1018. pa_doRcv:
  1019.         mov     di,offset rcv_buffno
  1020.         call    get_number
  1021.  
  1022.         mov     di,offset rcv_buffsz
  1023.         call    get_number
  1024.         jmp     parse_args_l
  1025.  
  1026.  
  1027. pa_doTrans:
  1028.         mov     di,offset xmt_buffno
  1029.         call    get_number
  1030.  
  1031.         mov     di,offset xmt_buffsz
  1032.         call    get_number
  1033.         jmp     parse_args_l
  1034.  
  1035.  
  1036. pa_doext:                       ;set up for HMA
  1037.         or      options,options_HMA   ;indicate we want to run up there
  1038.         jmp     parse_args_l
  1039.  
  1040.  
  1041. parse_args      endp
  1042.  
  1043.  
  1044.     public    print_parameters
  1045. print_parameters    proc
  1046.         mov     di,offset int_no
  1047.         mov     dx,offset int_no_name
  1048.         call    print_number
  1049.  
  1050.         mov     di,offset BasePrt
  1051.         mov     dx,offset BaseName
  1052.         call    print_number
  1053.  
  1054.         mov     di,offset DMAPrt
  1055.         mov     dx,offset DMAName
  1056.         call    print_number
  1057.  
  1058.         mov     di,offset rcv_buffno
  1059.         mov     dx,offset rcv_buffnoname
  1060.         call    print_number
  1061.  
  1062.         mov     di,offset rcv_buffsz
  1063.         mov     dx,offset rcv_buffszname
  1064.         call    print_number
  1065.  
  1066.         mov     di,offset xmt_buffno
  1067.         mov     dx,offset xmt_buffnoname
  1068.         call    print_number
  1069.  
  1070.         mov     di,offset xmt_buffsz
  1071.         mov     dx,offset xmt_buffszname
  1072.         call    print_number
  1073.  
  1074.     ret
  1075.  
  1076. print_parameters    endp
  1077.  
  1078.  
  1079.  
  1080.  
  1081. inv_DMA         db      "Invalid DMA channel number.",CR,LF,"$"
  1082. init_errmsg     db      "Lance initialisation failed.",CR,LF,"$"
  1083. inv_buff        db      "Invalid buffer specification.",CR,LF,"$"
  1084. HMAnoHIMEM      db      "HMA not available: HIMEM.SYS not installed.",CR,LF,"$"
  1085. HMAnotavail     db      "HMA not available.",CR,LF,"$"
  1086. HMAalloc        db      "Using extended memory (HMA).",CR,LF,"$"
  1087. HMAtoobig       db      "Buffers exceed HMA size.",CR,LF,"$"
  1088. HMAmsg_1        db      "/X configured $"
  1089. HMAmsg_2        db      " receive buffers of length $"
  1090. HMAmsg_3        db      ".",CR,LF,"$"
  1091.  
  1092.                 public  etopen
  1093. etopen          proc    near
  1094.                 assume  ds:code
  1095.  
  1096.         extrn    flagbyte: byte
  1097.                 or      flagbyte,CALLED_ETOPEN
  1098.  
  1099.                 test    parse_err,0ffh  ;any parsing error?
  1100.                 jnz     eto_errexit2    ;yes, give up
  1101.  
  1102.                 cmp     packet_int_no,0
  1103.                 mov     dx,offset usage_msg
  1104.                 jz      eto_errexit
  1105.  
  1106.  
  1107.  
  1108. ; check DMA port
  1109.                 mov     al,DMAPrt
  1110.                 or      al,al
  1111.                 jb      eto_invalid_DMA ;should not be negative
  1112.                 cmp     al,7
  1113.                 jna     eto_DMA_ok
  1114.  
  1115. eto_invalid_DMA:
  1116.                 mov     dx,offset inv_DMA
  1117.  
  1118. eto_errexit:
  1119.                 mov     ah,9
  1120.                 int     21h
  1121. eto_errexit2:
  1122.                 stc
  1123.                 ret
  1124.  
  1125. eto_DMA_ok:
  1126. ; check receive buffers
  1127.                 mov     bx,rcv_buffno
  1128.                 call    do_power_of_2
  1129.                 cmp     ax,128
  1130.                 jg      eto_inv_Buff
  1131.                 or      ax,ax                   ;must have something!
  1132.                 jz      eto_inv_Buff
  1133.                 mov     rcv_bufflog,cl
  1134.                 mov     rcv_buffno,ax
  1135.  
  1136.                 mov     ax,rcv_buffsz   ;check buffer size
  1137.                 cmp     ax,100          ;at least that big
  1138.                 jg      eto_rcvsz_1
  1139.                 mov     ax,100
  1140. eto_rcvsz_1:
  1141.                 cmp     ax,GIANT+4      ;biggest packet plus fcs
  1142.                 jl      eto_rcvsz_2     ;does not exceed
  1143.                 mov     ax,GIANT+4      ;take maximum
  1144. eto_rcvsz_2:
  1145.                 mov     rcv_buffsz,ax
  1146.  
  1147. ; check transmit buffers
  1148.                 mov     bx,xmt_buffno
  1149.                 call    do_power_of_2
  1150.                 or      ax,ax                   ;must have something!
  1151.                 jz      eto_inv_Buff
  1152.                 cmp     ax,128
  1153.                 jna     eto_xmt_buffok
  1154.  
  1155. eto_inv_Buff:
  1156.                 mov     dx,offset inv_Buff
  1157.                 jmp     eto_errexit
  1158.  
  1159. eto_xmt_buffok:
  1160.                 mov     xmt_bufflog,cl
  1161.                 mov     xmt_buffno,ax
  1162.  
  1163.                 mov     ax,xmt_buffsz   ;check buffer size
  1164.                 cmp     ax,RUNT         ;at least that big
  1165.                 jg      eto_xmtsz_1
  1166.                 mov     ax,0            ;else don't use
  1167. eto_xmtsz_1:
  1168.                 cmp     ax,GIANT        ;biggest packet w/o fcs
  1169.                 jl      eto_xmtsz_2     ;does not exceed
  1170.                 mov     ax,GIANT        ;take maximum
  1171. eto_xmtsz_2:
  1172.                 mov     xmt_buffsz,ax
  1173.                 mov     xmt_buffsz_r,ax ;again for our resident part
  1174.                 neg     ax
  1175.                 mov     xmt_buffsz_rn,ax ;times -1 for resident part
  1176.  
  1177. ; set RAP & RDP addresses
  1178.                 mov     ax,BasePrt
  1179.                 add     ax,0ch
  1180.                 mov     RDP,ax
  1181.                 add     ax,02h
  1182.                 mov     RAP,ax
  1183.  
  1184.  
  1185. ; this code is from Russell Nelson's packet driver skeleton.
  1186. ; Need it here, since we won't return from etopen: as soon as the
  1187. ; receiver is started, this place may get clobbered with Ethernet packets
  1188.  
  1189.         mov     ah,35h                  ;remember their packet interrupt.
  1190.         mov     al,packet_int_no
  1191.         int     21h
  1192.         mov     their_isr.offs,bx
  1193.         mov     their_isr.segm,es
  1194.  
  1195.         mov     ah,25h                  ;install our packet interrupt
  1196.         mov     dx,offset our_isr
  1197.         int     21h
  1198.  
  1199.                 call    set_recv_isr    ;intercept interrupts
  1200.  
  1201.  
  1202. ; Now we decide whether we will run in the HMA (above 1 MB) before
  1203. ; we do any calculations involving real addresses
  1204.  
  1205.                 test    options,options_HMA  ;will we?
  1206.                 jnz     eto_tryHMA      ;yes
  1207.                 jmp     eto_HMAok       ;no...
  1208.  
  1209. ; first check of HIMEM.SYS is installed and if we can globally
  1210. ; enable the HMA
  1211. eto_tryHMA:
  1212.                 mov     ax,4300h
  1213.                 int     2Fh             ; Is an XMS Driver installed?
  1214.                 mov     dx,offset HMAnoHIMEM    ;error message in case...
  1215.                 cmp     al,80h
  1216.                 jne     eto_noHMA       ;no...
  1217.                 mov     ax,4310h
  1218.                 int     2fh             ;obtain XMS control addr
  1219.                 mov     word ptr XMSctl,bx      ;save entry point
  1220.                 mov     word ptr XMSctl+2,es
  1221.  
  1222.                 mov     dx,0ffffh       ;allocate whole HMA
  1223.                 mov     ah,1
  1224.                 call    XMSctl
  1225.                 mov     dx,offset HMAnotavail   ;error msg in case...
  1226.                 cmp     ax,1
  1227.                 jne     eto_noHMA               ;not available
  1228.                 mov     ah,3                    ;global enable A20 line
  1229.                 call    XMSctl
  1230.                 cmp     ax,1                    ;ok?
  1231.                 je      eto_HMA_enabled
  1232.  
  1233. eto_noHMA:
  1234.                 mov     ah,9
  1235.                 int     21h                     ;error msg addr in dx!
  1236.                 and     options,not options_HMA ;turn off HMA bit
  1237.                 jmp     eto_HMAok               ;continue as usual
  1238.  
  1239. eto_HMA_enabled:
  1240. ;               mov     dx,offset HMAalloc
  1241. ;               mov     ah,9
  1242. ;               int     21h                     ;confirm
  1243.  
  1244.  
  1245. ; maximize the receive buffer space to utilise the whole HMA:
  1246. ;  1. calculate remaining space excluding receive buffers and descriptors
  1247. ;  2. start with 128 receive buffers
  1248. ;  3. calculate remaining space for buffers
  1249. ;  4. divide by number of buffers to obtain (even) buffer size
  1250. ;  5. if size inferior to defaulted or specified size half number
  1251. ;     of buffers and restart on step 2.
  1252.  
  1253.                 mov     bx,0fff0h       ;total HMA size
  1254.                 sub     bx,offset FirstDescr    ;minus resident code
  1255.  
  1256.                 mov     ax,xmt_buffsz   ;xmit buffer size
  1257.                 add     ax,8            ;plus descriptor
  1258.                 mul     xmt_buffno      ;=total xmit space
  1259.                 or      dx,dx           ;not more than 64k!
  1260.                 jnz     try_err         ;ooops
  1261.  
  1262.                 sub     bx,ax           ;remaining space without recv
  1263.                 jc      try_err         ;must be positive!
  1264.  
  1265.                 mov     cx,128          ;try 128 buffers
  1266. try_lp:
  1267.                 mov     ax,cx           ;number of buffers
  1268.                 shl     ax,3            ;8 bytes long
  1269.                 sub     ax,bx
  1270.                 neg     ax              ;remaining space for buffers
  1271.  
  1272.                 xor     dx,dx           ;accumulator extension
  1273.                 div     cx              ;calculate buffer length
  1274.                 and     ax,0fffeh       ;even length
  1275.                 cmp     ax,rcv_buffsz   ;long enough?
  1276.                 jnb     try_ok          ;yes...
  1277.                 shr     cx,1            ;else half number of buffers
  1278.                 jnz     try_lp          ;and retry
  1279.  
  1280. try_err:
  1281.                 mov     dx,offset HMAtoobig
  1282.                 jmp     eto_errexit
  1283.  
  1284. try_ok:
  1285.                 cmp     ax,GIANT+4      ;maximum size
  1286.                 jng     try_ok_2        ;does not exceed
  1287.                 mov     ax,GIANT+4      ;else maximum length
  1288. try_ok_2:
  1289.                 mov     rcv_buffno,cx
  1290.                 mov     rcv_buffsz,ax
  1291.                 mov     bx,cx
  1292.                 call    do_power_of_2   ;have to do it again
  1293.                 mov     rcv_bufflog,cl
  1294.  
  1295.  
  1296.  
  1297.                 mov     dx,offset HMAmsg_1
  1298.                 mov     ah,9
  1299.                 int     21h
  1300.  
  1301.                 mov     ax,rcv_buffno
  1302.                 xor     dx,dx
  1303.                 call    decout
  1304.  
  1305.                 mov     dx,offset HMAmsg_2
  1306.                 mov     ah,9
  1307.                 int     21h
  1308.  
  1309.                 mov     ax,rcv_buffsz
  1310.                 xor     dx,dx
  1311.                 call    decout
  1312.  
  1313.                 mov     dx,offset HMAmsg_3
  1314.                 mov     ah,9
  1315.                 int     21h
  1316.  
  1317.  
  1318. ; la demarche a suivre:
  1319. ; we copy ourselves into the HMA completely, format all the
  1320. ; descriptors, correct the interrupt addr and exit to DOS
  1321.  
  1322.                 mov     ax,cs
  1323.                 mov     orgseg,ax       ;save original segment
  1324.                 les     di,dword ptr HMAaddr ;that's where we will be
  1325.                 mov     cx,offset end_code  ;length(!) of code to be copied
  1326.                 mov     si,10h          ;start at offset 10
  1327.                 sub     cx,si           ;correct length
  1328.                 rep     movsb           ;copy us
  1329.                 push    HMAaddrS        ;our new segment
  1330. ; careful: here comes a jump!
  1331.                 call   setcs            ;we're in the HMA
  1332.                 push    cs
  1333.                 pop     ds              ;our data as well
  1334.  
  1335.  
  1336.  
  1337. eto_HMAok:
  1338. ; get linear address for receive buffer descriptor start
  1339.                 push    ds
  1340.                 mov     ax,offset FirstDescr
  1341.                 pop     dx
  1342.                 call    seg2lin
  1343.  
  1344. ; Store in Init Block
  1345.                 mov     IBrdraL,ax
  1346.                 mov     IBrdraH,dx
  1347.  
  1348. ; calculate linear address of first buffer
  1349.                 mov     bx,offset FirstDescr
  1350.                 mov     rbfstart,bx
  1351.                 mov     rbfcurr,bx
  1352.  
  1353.                 mov     ax,rcv_buffno
  1354.                 push    ds
  1355.                 pop     dx
  1356.                 add     ax,xmt_buffno   ;result is still in segment
  1357.                 shl     ax,3            ;times eight
  1358.                 add     ax,bx           ;won't leave segment!
  1359.                 call    seg2lin         ;convert to linear addr
  1360.                 mov     linaddrL,ax     ;first available buffer addr
  1361.                 mov     linaddrH,dx
  1362.  
  1363. ; format receive buffer descriptors
  1364.                 mov     si,rcv_buffsz   ;buffer size
  1365.                 mov     cx,rcv_buffno   ;number of buffers
  1366.                 mov     dl,RBown        ;flags
  1367. eto_rcvloop:
  1368.                 call    format_descr
  1369.                 add     bx,8
  1370.                 loop    eto_rcvloop
  1371.  
  1372.  
  1373. ;set transmit descriptor ring address
  1374.                 push    ds
  1375.                 mov     ax,bx
  1376.                 pop     dx
  1377.                 call    seg2lin
  1378.                 mov     IBtdraL,ax
  1379.                 mov     IBtdraH,dx
  1380.  
  1381. ; format transmit buffer descriptors
  1382.                 mov     tbfstart,bx             ;remember start
  1383.                 mov     tbfcurr,bx
  1384.                 mov     dl,0                    ;initial flags
  1385.                 mov     cx,xmt_buffno           ;number of buffers
  1386.                 mov     si,xmt_buffsz           ;buffer size
  1387. eto_xmtloop:
  1388.                 call    format_descr
  1389.                 add     bx,8
  1390.                 loop    eto_xmtloop
  1391.                 mov     tbfend,bx               ;remember end
  1392.  
  1393.  
  1394. ; finish initialisation block
  1395.                 mov     al,rcv_bufflog  ;# of rcv buffers
  1396.                 shl     al,5
  1397.                 mov     IBrdraHF,al
  1398.  
  1399.                 mov     al,xmt_bufflog  ;# of xmt buffers
  1400.                 shl     al,5
  1401.                 mov     IBtdraHF,al
  1402.  
  1403. ; copy Ethernet address out of ROM
  1404.                 mov     cx,EADDR_LEN
  1405.                 push    ds
  1406.                 pop     es
  1407.                 mov     di,offset IBpadr
  1408.                 mov     dx,BasePrt
  1409. eto_addrloop:
  1410.                 in      ax,dx
  1411.                 inc     dx
  1412.                 inc     dx
  1413.                 stosb
  1414.                 loop    eto_addrloop
  1415.  
  1416. ; init DMA controller
  1417.                 test    sys_features,MICROCHANNEL ;running on a PS/2?
  1418.                 jnz     eto_DMA_done    ;yes, no DMA
  1419.  
  1420.                 cmp     DMAPrt, 3      ; Which DMAC - 1 or 2 ?
  1421.                 ja      SetupDMAC2    ; DMAC 2
  1422.  
  1423.                 mov     dx,DMAC1ModeReg ;addr of mode reg 1
  1424.                 mov     al,DMAPrt    ;DMA number
  1425.                 or      al,DMACascade   ;or in mode reg bits
  1426.                 out     dx,al
  1427.                 jmp     $+2
  1428.                 and     al,3            ;leave only DMA channel #
  1429.                 mov     dx,DMAC1MaskReg ;mask register 1 addr
  1430.                 out     dx,al           ;clear the DMA channel
  1431.                 jmp     eto_DMA_done
  1432.  
  1433. SetupDMAC2:
  1434.                 mov     dx,DMAC2ModeReg ;addr of mode reg 2
  1435.                 mov     al,DMAPrt    ;DMA number
  1436.                 sub     al, 4        ;Adjust DMA channel number
  1437.                 or      al,DMACascade   ;or in mode reg bits
  1438.                 out     dx,al
  1439.                 jmp     $+2
  1440.                 and     al,3            ;leave only DMA channel #
  1441.                 mov     dx,DMAC2MaskReg ;mask register 2 addr
  1442.                 out     dx,al           ;clear the DMA channel
  1443.                 jmp     eto_DMA_done
  1444.                 
  1445. eto_DMA_done:
  1446.  
  1447. ; stop the Lance, sets required bits in CSR3 as well
  1448.                 call    reset_interface
  1449.  
  1450. ; Give the LANCE the address of the initialisation block
  1451.                 call    LoadInitBlock
  1452.  
  1453. ; init the controller and wait for completion
  1454.                 call    InitLance
  1455.  
  1456. eto_init_ok:
  1457.                 test    options,options_HMA ;are we in HMA?
  1458.                 jz      eto_tsr         ;no, use TSR code
  1459.                 xor     ax,ax
  1460. ; correct the packet and hardware interrupt addresses
  1461.                 mov     es,ax
  1462.                 xor     bh,bh
  1463.                 mov     bl,packet_int_no
  1464.                 shl     bx,2            ;point to interrupt vector
  1465.                 push    cs
  1466.                 pop     es:[bx+2]
  1467.  
  1468.                 mov     bx,int_no       ;card interrupt
  1469.                 add     bx,68h          ;assume above 8
  1470.                 cmp     bx,8+68h        ;is it?
  1471.                 jnb     eto_HMA_int_ok  ;yes...
  1472.                 sub     bx,60h          ;PS/2 can use interrupt < 8
  1473. eto_HMA_int_ok:
  1474.                 shl     bx,2            ;point to interrupt vector
  1475.                 push    cs
  1476.                 pop     es:[bx+2]
  1477.  
  1478. ; Now start the receiver and exit to DOS
  1479.         call    outofHMA                ;out of danger zone (buffers!)
  1480.         mov     bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON  ; ...SET...
  1481.         call    wrcsr0                                      ; ...GO!
  1482.         int     20h                     ;exit...
  1483.  
  1484.  
  1485. eto_tsr:
  1486. ;calculate end of resident part (relative to pgm start)
  1487.                 mov     ax,linaddrL
  1488.                 mov     dx,linaddrH
  1489.                 add     ax,15           ;round to paragraph
  1490.                 adc     dl,0
  1491.                 shr     ax,4
  1492.                 shl     dl,4
  1493.                 or      ah,dl
  1494.                 mov     dx,ds           ;minus pgm start addr
  1495.                 sub     ax,dx
  1496.                 push    ax              ;save the address
  1497.  
  1498.  
  1499. ; again some code from the packet driver skeleton...
  1500.  
  1501.         mov     ah,49h                  ;free our environment, because
  1502.         mov     es,phd_environ          ;  we won't need it.
  1503.         int     21h
  1504.  
  1505.         mov     bx,1                    ;get the stdout handle.
  1506.         mov     ah,3eh                  ;close it in case they redirected it.
  1507.         int     21h
  1508.  
  1509. ;        call    setup_isr       ;Install LANCE lockup isr
  1510.  
  1511.         mov     ax,csr0                                     ; READY...
  1512.         mov     bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON  ; ...SET...
  1513.         jmp     eto_go                                      ; ...GO!
  1514. etopen          endp
  1515.  
  1516.  
  1517. do_power_of_2   proc    near
  1518. ; adjust bx to valid # of buffers.
  1519. ; on exit: ax=fitting number, cx=log2(ax)
  1520.                 mov     cx,7            ;allow 7 shifts
  1521.                 mov     ax,bx
  1522. dpw2_loop:
  1523.                 cmp     ax,1
  1524.                 je      dpw2_done
  1525.                 shr     ax,1
  1526.                 loop    dpw2_loop
  1527. dpw2_done:
  1528.                 mov     ax,7
  1529.                 sub     ax,cx           ;get number of shifts
  1530.                 mov     cx,ax
  1531.  
  1532.                 mov     ax,1
  1533.                 jcxz    dpw2_ret
  1534.                 shl     ax,cl
  1535. dpw2_ret:
  1536.                 ret
  1537. do_power_of_2   endp
  1538.  
  1539.  
  1540.  
  1541.  
  1542.  
  1543. format_descr    proc    near
  1544. ; format buffer descriptor pointed to by [bx]
  1545. ; si=buffer size, dl=flags
  1546.                 push    dx              ;save flags
  1547.                 mov     ax,linaddrL     ;next available buffer addr
  1548.                 mov     dx,linaddrH
  1549.                 mov     RBadrL[bx],ax   ;buffer addr
  1550.                 mov     RBadrH[bx],dx
  1551.                 add     ax,si           ;point to next available addr
  1552.                 adc     dx,0
  1553.                 mov     linaddrL,ax
  1554.                 mov     linaddrH,dx
  1555.                 mov     ax,si           ;get buffer size
  1556. ;               or      ah,0f0h         ;reserved bits to 1
  1557.                 neg     ax              ;two's complement
  1558.                 mov     RBbcnt[bx],ax
  1559.                 pop     dx              ;restore flags
  1560.                 mov     RBflags[bx],dl
  1561.                 ret
  1562. format_descr    endp
  1563.             
  1564.  
  1565. outofHMA        proc    near    ;leave the HMA
  1566.                 test    options,options_HMA ;are we in it?
  1567.                 jz      ooHret          ;no...
  1568.                 push    orgseg
  1569.                 call    setcs
  1570.                 push    cs
  1571.                 pop     ds
  1572. ooHret:
  1573.                 ret
  1574. outofHMA        endp
  1575.  
  1576.  
  1577. setcs           proc    near
  1578.                 db      0cbh            ;RET FAR (!)
  1579. setcs           endp
  1580.  
  1581. disp_hex_num    PROC    NEAR
  1582.  
  1583.         push    ax
  1584.         push    bx
  1585.         push    cx
  1586.         mov     bx,ax
  1587.         mov     cx,4
  1588. start:
  1589.         push    cx
  1590.         mov     cl,4
  1591.         rol     bx,cl
  1592.         push    bx
  1593.         and     bl,0fh
  1594.         mov     al,bl
  1595.         cmp     al,09
  1596.         jg      letter
  1597. digit:
  1598.         add     al,48
  1599.         jmp     print_num
  1600. letter:
  1601.         add     al,55
  1602. print_num:
  1603.         mov     ah,14
  1604.         int     10h
  1605.         pop     bx
  1606.         pop     cx
  1607.         loop    start
  1608.  
  1609.         mov     al,20h
  1610.         mov     ah,14
  1611.         int     10h
  1612.  
  1613.         pop     cx
  1614.         pop     bx
  1615.         pop     ax
  1616.  
  1617.         ret
  1618.  
  1619. ;        mov     ax,4c00h        ; Load DOS exit function
  1620. ;        int     21h             ; call DOS
  1621.  
  1622. disp_hex_num    ENDP
  1623.  
  1624. end_code        equ     $
  1625.  
  1626. PUBLIC  mc_end
  1627. mc_end  db      0
  1628.  
  1629. code    ends
  1630.         end
  1631.  
  1632.  
  1633.